package client.ftp.impl;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.SftpProgressMonitor;

import client.ftp.IFtpClient;
import client.ftp.RemoteFileAttr;
import core.FormDialog;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import util.FTPUtil;
import util.FormatUtil;

public class SftpClientImpl implements IFtpClient {

	private static final Logger log=LoggerFactory.getLogger(SftpClientImpl.class);

	private static final String CLIENT_NAME="SFTP";

	private static final String FILE_DATE_FORMAT_STR = "yyyy-MM-dd HH:mm:ss";

	private FTPUtil ftpUtil;

	private ChannelShell shell;

	private Thread shellOutputReadThread;

	@Override
	public void close() throws IOException {
		if(shellOutputReadThread!=null && shellOutputReadThread.isAlive()){
			shellOutputReadThread.interrupt();
		}
		if(shell!=null){
			shell.disconnect();
		}
		if(ftpUtil!=null){
			ftpUtil.close();
		}
	}

	@Override
	public String getName() {
		return CLIENT_NAME;
	}

	@Override
	public boolean init(RemoteShellOutputListener remoteShellOutputListener) {
		log.info("初始化客户端组件！");
		if(createConnection()){
			//监听shell输出
			shellOutputReadThread = new Thread(()->{
				try {
					InputStreamReader input = new InputStreamReader(shell.getInputStream(),"UTF-8");
					char[] charBuf = new char[1024];
					int len;
					while((len=input.read(charBuf))!=-1) {
						String tmp=new String(charBuf,0,len);
						tmp=tmp.replaceAll("\033\\[\\d+(;\\d+)*m",""); //展示不支持vt100控制字符，移除之
						remoteShellOutputListener.handle(tmp);
					}
				} catch (Exception e) {}
			});
			shellOutputReadThread.start();
			return true;
		}
		return false;
	}

	private boolean createConnection() {
		log.info("创建连接！");
		TextField hostTextField = new TextField("127.0.0.1");
		TextField portTextField = new TextField("22");
		TextField userTextField = new TextField();
		PasswordField pwdTextField = new PasswordField();
		FormDialog newConnForm = new FormDialog("新建链接"
				,new FormDialog.Item("主机：", hostTextField)
				,new FormDialog.Item("端口：", portTextField)
				,new FormDialog.Item("用户名：", userTextField)
				,new FormDialog.Item("密码：", pwdTextField));
		Optional<Boolean> result = newConnForm.showAndWait();
		if(result.isPresent()) {
			String host = hostTextField.getText();
			int port = Integer.valueOf(portTextField.getText());
			String username = userTextField.getText();
			String password = pwdTextField.getText();
			log.info("连接参数 -> host:"+host+",port:"+port);
			ftpUtil=FTPUtil.getSFTPChannel(host, port, username, password);
			ftpUtil.run((ChannelSftp channelSftp)->{
				shell = (ChannelShell)channelSftp.getSession().openChannel("shell");
				shell.connect();
			});
			return true;
		}
		return false;
	}

	@Override
	public void exeCmd(String cmd) {
		try {
			PrintStream commander = new PrintStream(shell.getOutputStream(), true, "UTF-8");
			commander.println(cmd);
			commander.flush();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public void upload(String localFilePath,String remoteFilePath){
		ftpUtil.run((ChannelSftp channelSftp)->{
            try {
				channelSftp.put(localFilePath, remoteFilePath, new SftpProgressMonitor() {

					@Override
					public void init(int op, String src, String dest, long max) {
						log.info("【开始上传】"+src+" -> "+dest+" total:"+max);
					}

					@Override
					public void end() {
						log.info("【传输完成】");
					}

					@Override
					public boolean count(long count) {
						log.info("【已传输】-> "+count);
						return false;
					}
				});
			} catch (Exception e) {
				e.printStackTrace();
			}
		});
	}

	public void download(String remoteFilePath,String localFilePath){
		ftpUtil.run((ChannelSftp channelSftp)->{
			channelSftp.get(remoteFilePath, localFilePath, new SftpProgressMonitor() {

				@Override
				public void init(int op, String src, String dest, long max) {
					log.info("【开始】"+src+" -> "+dest+" total:"+max);
				}

				@Override
				public void end() {
					log.info("【传输完成】");
				}

				@Override
				public boolean count(long count) {
					log.info("【已传输】-> "+count);
					return false;
				}
			});
		});
	}

	@Override
	public String pwd() {
		StringBuilder strBuilder=new StringBuilder();
		ftpUtil.run((ChannelSftp channelSftp)->{
			String currPath=channelSftp.pwd();
			strBuilder.append(currPath);
		});
		return strBuilder.toString();
	}

	@Override
	public List<RemoteFileAttr> listFile(String remotePath) {
		List<RemoteFileAttr> fileList=new ArrayList<>();
		ftpUtil.run((ChannelSftp channelSftp)->{
			@SuppressWarnings("unchecked")
			Vector<ChannelSftp.LsEntry> files = channelSftp.ls(remotePath);
			for(ChannelSftp.LsEntry fileEntry:files){
				String fileName = fileEntry.getFilename();
				if(".".equals(fileName)||"..".equals(fileName)) continue;
				String fileSize = FormatUtil.formatFileSize(fileEntry.getAttrs().getSize());
				String lastUpdateTime = FormatUtil.formatDate(fileEntry.getAttrs().getMTime()*1000L, FILE_DATE_FORMAT_STR);
				String permissionsStr = fileEntry.getAttrs().getPermissionsString();
				boolean isDir = fileEntry.getAttrs().isDir();
				fileList.add(new RemoteFileAttr(fileName, fileSize, lastUpdateTime, permissionsStr, isDir));
			}
		});
		return fileList;
	}

	@Override
	public void delFile(String filePath,boolean isDir) {
		ftpUtil.run((ChannelSftp channelSftp)->{
			if(isDir){
				channelSftp.rmdir(filePath);
			}else{
				channelSftp.rm(filePath);
			}
		});
	}

	@Override
	public void sendHotKey(HotKey hotKey) {
		if(HotKey.CTRL_C.equals(hotKey)){
			ftpUtil.run((ChannelSftp channelSftp)->{
				channelSftp.sendSignal("2"); //信号2代表中断进程，等同于ctrl+c
			});
		}
	}
}
